#include "ota_version.h"



/**
 * 计算文件的SHA1哈希值
 * @param file_path 文件路径
 * @return 文件的SHA1哈希值（十六进制字符串），需要调用者释放内存
 */
char* calculate_file_sha1(const char* file_path) {
    if (file_path == NULL) {
        return NULL;
    }
    
    // 打开文件
    FILE* file = fopen(file_path, "rb");
    if (file == NULL) {
        return NULL;
    }
    
    // 初始化SHA1上下文
    SHA_CTX sha1_ctx;
    SHA1_Init(&sha1_ctx);
    
    // 逐块读取文件并更新哈希值
    unsigned char buffer[1024];
    size_t bytes_read;
    while ((bytes_read = fread(buffer, 1, sizeof(buffer), file)) > 0) {
        SHA1_Update(&sha1_ctx, buffer, bytes_read);
    }
    
    // 获取最终哈希值
    unsigned char hash[SHA_DIGEST_LENGTH];
    SHA1_Final(hash, &sha1_ctx);
    
    // 关闭文件
    fclose(file);
    
    // 转换为十六进制字符串
    char* result = (char*)malloc(SHA_DIGEST_LENGTH * 2 + 1);
    if (result == NULL) {
        return NULL;
    }
    
    for (int i = 0; i < SHA_DIGEST_LENGTH; i++) {
        sprintf(&result[i * 2], "%02x", hash[i]);
    }
    
    return result;
}


/**
 * @brief 检查并更新版本
 * 
 * 1  用httpcurl访问ota服务器 获得版本的json 
 * 2  解析json 获得版本号
 * 3  比较版本号  如果当前版本号大于远端的 则退出   
 * 4  本地小  下载远端的程序文件
 * 5  基于下载的文件生成验证码  还和 远端的验证码进行对比
 * 6  如果一致  重启  （程序替换和新程序启动 用shell解决)
 * 7  如果不一致 删除文件 退出
 * 
 */
void  ota_version_check_and_update(void)
{
//  * 1  用httpcurl访问ota服务器 获得版本的json 
     
     response_body_t *response_body = ota_http_curl_get(VERSION_INFO_URL);
     if(response_body == NULL)
     {
         return;
     }

//  * 2  解析json 获得版本号
     log_info("ota json: %s", response_body->response_str);
     cJSON *root= cJSON_Parse(response_body->response_str);
     cJSON *major_cjson = cJSON_GetObjectItem(root, "major");
     cJSON *minor_cjson = cJSON_GetObjectItem(root, "minor");
     cJSON *patch_cjson = cJSON_GetObjectItem(root, "patch");
     cJSON *sha1_cjson = cJSON_GetObjectItem(root, "sha1");
      int major = major_cjson->valueint;
      int minor = minor_cjson->valueint;
      int patch = patch_cjson->valueint;
      char *sha1 = sha1_cjson->valuestring;

//  * 3  比较版本号  如果当前版本号大于远端的 则退出  
     log_info("ota server version info: %d.%d.%d ",major,minor,patch);
     log_info("当前版本号:%d.%d.%d",VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH);
     if( VERSION_MAJOR > major
        ||(VERSION_MAJOR == major && VERSION_MINOR > minor)
        ||(VERSION_MAJOR == major && VERSION_MINOR == minor && VERSION_PATCH >= patch)
    )
    {
        log_info("没有发现更新的版本..");
        free( response_body->response_str);
        free( response_body );
        cJSON_Delete(root);
        return ;
    }
//  * 4  如果本地小  下载远端的程序文件
    unlink(VERSION_INFO_FILE_PATH);
    log_info("发现更新的版本..");
    int ret= ota_http_curl_download(VERSION_INFO_DOWNLOAD_URL, VERSION_INFO_FILE_PATH);
    if(ret != 0)
    {
        log_error("下载更新文件失败..");
        free( response_body->response_str);
        free( response_body );
        cJSON_Delete(root);
        return ;
    }

//  * 5  基于下载的文件生成验证码  还和 远端的验证码进行对比
    char* sha1_local= calculate_file_sha1(VERSION_INFO_FILE_PATH);
    if(strcmp(sha1_local, sha1 )==0)
    {
//  * 6  如果一致  重启  （程序替换和新程序启动 用shell解决)
        log_info("下载文件验证通过,sha1 码..%s:",sha1_local);
        reboot(RB_AUTOBOOT);
    }
    else
    {
        //  * 7  如果不一致 删除文件 退出
        log_error("下载文件验证失败,sha1 码不一致..%s:%s",sha1_local,sha1);
        free( response_body->response_str);
        free( response_body );
        cJSON_Delete(root);
        unlink(VERSION_INFO_FILE_PATH);
        return ;
    }

    return ;

}


/**
 * @brief 每日检查
 */
void ota_version_daily_check(void)
{
    while(1)
    {
        sleep(24*60*60);//等待一天
        ota_version_check_and_update();
    }
}


/**
 * @brief 打印当前本地版本号
 */
void ota_version_print(void)
{
    printf("当前版本号:%d.%d.%d",VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH);

}